
`include "common_header.verilog"

//  *************************************************************************
//   File : dskw_buf_wr.v
//  *************************************************************************
//   This program is controlled by a written license agreement.
//   Unauthorized Reproduction or Use is Expressly Prohibited. 
// 
//  Copyright (c) 2005 Morethanip GmbH
//  info@morethanip.com
//  *************************************************************************
//  Version: $Id: dskw_buf_wr.v,v 1.6 2017/06/07 14:37:54 dk Exp $ 
//  Author : Muhammad Anisur Rahman
//  *************************************************************************
//  Description:
// 
//   10 Gigabit Ethernet XGXS Receive Synchronization
// 
//  *************************************************************************

module dskw_buf_wr (

   reset,
   clk,
  `ifdef USE_CLK_ENA
   clk_ena,
  `endif   
   enable_deskew,
   align_done,
   rx_sync,
   kchar,
   data,
   buffer_rst,
   rd_buffer_ack,
   ff_afull,
   ff_wren);

input   reset;          //  Asynchronous Reset
input   clk;            //  156.25MHz Line Clock
`ifdef USE_CLK_ENA
input   clk_ena;
`endif
input   enable_deskew;  //  Enable Lane Deskew 
input   align_done;     //  Alignment completed
input   [3:0] rx_sync;  //  Receive Synchronized
input   kchar;          //  Special Character Indication
input   [7:0] data;     //  Decoded Data
output   buffer_rst;    //  Buffer Synchronous Reset
input   rd_buffer_ack;  //  Read Clock Acknowledge
input   [3:0] ff_afull; //  Buffer Almost Full
output   ff_wren;       //  Buffer Write Enable

reg     buffer_rst; 
wire    ff_wren; 

parameter STM_TYP_IDLE       = 3'h0;
parameter STM_TYP_WAIT_A     = 3'h1;
parameter STM_TYP_WAIT_ALIGN = 3'h2;
parameter STM_TYP_BUF_WR     = 3'h3;
parameter STM_TYP_BUF_RST    = 3'h4;
parameter STM_TYP_WAIT1      = 3'h5;
parameter STM_TYP_WAIT2      = 3'h6;
//parameter STM_TYP_WAIT3      = 3'h7;

reg     [2:0] nextstate; 
reg     [2:0] state; 

//  Clock Domain Synchronization
//  ----------------------------

wire    enable_deskew_reg2; 
wire    align_done_reg2; 
wire    rd_buffer_ack_reg2; 
wire    [3:0] ff_afull_reg2; 
wire    [3:0] rx_sync_reg2; 

//  Clock Domain Synchronization
//  ----------------------------

mtip_xsync #(3) U_SYSIGS (
        .data_in({rd_buffer_ack, align_done, enable_deskew}),
        .reset  (reset),
        .clk    (clk),
        .data_s ({rd_buffer_ack_reg2, align_done_reg2, enable_deskew_reg2}));

mtip_xsync #(4) U_SYAFULL (
        .data_in(ff_afull),
        .reset  (reset),
        .clk    (clk),
        .data_s (ff_afull_reg2));

mtip_xsync #(4) U_SYSYNC (
        .data_in(rx_sync),
        .reset  (reset),
        .clk    (clk),
        .data_s (rx_sync_reg2));


always @(posedge reset or posedge clk)
   begin : process_2
   if (reset == 1'b 1)
      begin
      state <= STM_TYP_IDLE;   
      end
   else
      begin
      
         `ifdef USE_CLK_ENA
            if(clk_ena == 1'b 1)
            begin
         `endif      
      
                state <= nextstate;   
      
         `ifdef USE_CLK_ENA
            end
         `endif      
      
      end
   end

always @(state or enable_deskew_reg2 or align_done_reg2 or rd_buffer_ack_reg2 or data
 or kchar or rx_sync_reg2 or ff_afull_reg2)
   begin : process_3
   case (state)
   STM_TYP_IDLE:
      begin
      if (enable_deskew_reg2 == 1'b 1 & rx_sync_reg2 == 4'b 1111)
         begin
         nextstate = STM_TYP_WAIT_A;   
         end
      else
         begin
         nextstate = STM_TYP_IDLE;   
         end
      end
   STM_TYP_WAIT_A:
      begin
      if (ff_afull_reg2 != 4'b 0000)
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else if (kchar == 1'b 1 & data == 8'h 7C)
         begin
         nextstate = STM_TYP_WAIT1; // STM_TYP_WAIT_ALIGN;   
         end
      else
         begin
         nextstate = STM_TYP_WAIT_A;   
         end
      end
   STM_TYP_WAIT1:
      begin
      if (ff_afull_reg2 != 4'b 0000)
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else
         begin
         nextstate = STM_TYP_WAIT2;   
         end
      end
   STM_TYP_WAIT2:
      begin
      if (ff_afull_reg2 != 4'b 0000)
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else
         begin
         nextstate = STM_TYP_WAIT_ALIGN; // STM_TYP_WAIT3;   
         end
      end
   //STM_TYP_WAIT3:
   //   begin
   //   if (ff_afull_reg2 != 4'b 0000)
   //      begin
   //      nextstate = STM_TYP_BUF_RST;   
   //      end
   //   else
   //      begin
   //      nextstate = STM_TYP_WAIT_ALIGN;   
   //      end
   //   end
   STM_TYP_WAIT_ALIGN:
      begin
      if (ff_afull_reg2 != 4'b 0000)
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else if (align_done_reg2 == 1'b 1 )
         begin
         nextstate = STM_TYP_BUF_WR;   
         end
      else
         begin
         nextstate = STM_TYP_WAIT_ALIGN;   
         end
      end
   STM_TYP_BUF_WR:
      begin
      if (ff_afull_reg2 != 4'b 0000)
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else if (align_done_reg2 == 1'b 0 )
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      else
         begin
         nextstate = STM_TYP_BUF_WR;   
         end
      end
   STM_TYP_BUF_RST:
      begin
      if (rd_buffer_ack_reg2 == 1'b 1 & ff_afull_reg2 == 4'b 0000)
         begin
         nextstate = STM_TYP_IDLE;   
         end
      else
         begin
         nextstate = STM_TYP_BUF_RST;   
         end
      end
   default:
      begin
      nextstate = STM_TYP_IDLE;
      end
   endcase
   end

//  Buffer Write Enable
//  -------------------

assign ff_wren = (nextstate==STM_TYP_WAIT1 | state == STM_TYP_BUF_WR | state == STM_TYP_WAIT_ALIGN) ? 1'b 1 : 1'b 0;


//  Buffer Reset
//  ------------

always @(posedge reset or posedge clk)
   begin : process_5
   if (reset == 1'b 1)
      begin
      buffer_rst <= 1'b 0;   
      end
   else
      begin
      
         `ifdef USE_CLK_ENA
            if(clk_ena == 1'b 1)
            begin
         `endif      

              if (nextstate == STM_TYP_BUF_RST)
                 begin
                 buffer_rst <= 1'b 1;   
                 end
              else
                 begin
                 buffer_rst <= 1'b 0;   
                 end

         `ifdef USE_CLK_ENA
            end
         `endif      
      
      end
   end

endmodule // module dskw_buf_wr